<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app" class="app">
    vue源码准备
</div>
<span>{{}}</span>
<!--这是一行注释,但是请不要删除 否则后果自负-->

<!--我是A, 上面哪行注释千万不能删除-->
<ul id="liBox">
    <li>[].slice.call(childNodes)</li>
    <li>Object.defineProperty</li>
    <li>Object.keys</li>
    <li>Object.hasOwnProperty</li>
    <li>node.nodeType</li>
    <li>createDocumentFragment</li>
</ul>

</body>
<script>
//    1.   [].slice.call(childNodes) 伪数组转换为数组
        //   Array.from
        //   Array.prototype.slice.call(arguments) 类数组转换成数组
//    伪数组 ==> 不能直接使用数组方法 但是内部有下标 长度

    //伪数组__proto__ 不指向Array 指向的是 对象object
    let lis = document.getElementsByTagName("li");
    console.log(lis);
    (function a() {
        console.log(arguments)
    })(1,2,3)

/*    let num = new Number(1); 创建一个number实例 进行赋值
    let num = 1; //字面量赋值
    console.log(num);// 1
    console.log(typeof num);//"number"  "object"*/

      let arr = [].slice.call(lis);
      console.log(arr);

      //Object上常用的API defineProperty keys hasOwnProperty assign
//    2.Object.defineProperty 方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。
/**
 * 定义属性
 * obj: 要增加或者修改属性的对象
 * prop: 属性名
 * descriptor: 属性描述
 * return  obj
 */
//Object.defineProperty(obj, prop, descriptor)

    //属性描述符
//        数据描述符
    //configurable: 布尔 --> 是否可配置
    //enumerable: 布尔 --> 是否可枚举
    //value: 默认值
    //writable: 布尔 --> 是否可重写

//    访问(存取)描述符
    //get //回调函数 根据其他属性,动态计算当前属性的值
    //set //回调函数 监听当前属性值是否发生改变 然后更新其他相关属性

let obj = {
    firstName: "A",
    lastName: "B"
};

Object.defineProperty(obj, "fullName", {
    enumerable: true,
    get(){//回调函数 根据其他属性,动态计算当前属性的值
        console.log("读取fullName");
        return this.firstName + "-" + this.lastName
    },
    set(newValue){//回调函数 监听当前属性值是否发生改变 然后更新其他相关属性
        console.log("set方法--->",newValue);//"C-D"
        let fullName = newValue.split("-");//["C","D"]
        this.firstName = fullName[0];
        this.lastName = fullName[1];
    }
});

Object.defineProperty(obj, "fullName1", {
    configurable: true,
    enumerable: false,
});
Object.defineProperty(obj, "fullName1", {
    enumerable: true, // Cannot redefine property: fullName1
    writable: false, // --> 是否可写
    value: "1234" //默认值
});

console.log(obj.fullName);//A-B
obj.firstName = "C";
console.log(obj.fullName);//C-B
obj.fullName = "E-F";
console.log(obj.firstName, obj.lastName);//E ,F


console.log("fullName1--->",obj.fullName1);
obj.fullName1 = "4567";
console.log("fullName1--->",obj.fullName1);
console.log(Object.keys(obj))

//    3.Object.keys //获取对象中所有属性名 返回属性名所组成的数组
//    for ..in    for ..of
    for(let key in obj){
        console.log("for-in==>","key:"+key,"value:"+obj[key]);//属性名 ;//属性值
    }
    for(let key of Object.keys(obj)){//obj is not iterable //obj 不是 可迭代的
//    for(let key of obj){//obj is not iterable //obj 不是 可迭代的
        console.log("for-in==>","key:"+key,"value:"+obj[key]);//属性名 ;//属性值
    }


    //可迭代的  []
let arr1 = ["a", "b", "c"];

for(let key in arr1){
    console.log(key,arr1[key]);//下标 ;//值
}
//for of 主要就是为了遍历iterator   for of是迭代器主要的消费者
for(let item of arr1){
    console.log(item);//下标 ;//值
}
//    4.object.hasOwnProperty

console.log("hasOwnProperty-->",obj.hasOwnProperty("fullName"));//true
console.log("hasOwnProperty-->",obj.hasOwnProperty("toString"))//false

//Number("1");
//String([]);

//1 ,"", true

//使用new关键字 可以把普通数据类型转换成object数据类型

//    5.node.nodeType 节点类型

/**
 * 节点   文档节点 document->(html)
 *       元素节点 element 1
 *       属性节点 attribute 2
 *       文本节点 text 3
 *       注释节点 comm  8
 */

//<div id="app" class="app">vue源码准备</div>
//<input v-model="name" type="text" placeholder="姓名">

let elementNode = document.getElementById("app");
//let attrNode = elementNode.getAttribute("id");//获取属性值
let attrNode = elementNode.getAttributeNode("id");//获取属性节点
let textNode = elementNode.firstChild;//获取文本节点
console.log(elementNode,attrNode,textNode);
console.log(elementNode.nodeType,attrNode.nodeType,textNode.nodeType)


//textNode.getAttribute("v-model")  -->name
console.dir(textNode);
//所有的节点都继承自Node
// Node上拥有一个nodeType


//    6.DocumentFragment 文档碎片
    //它被作为一个轻量版的 Document 使用，就像标准的document一样，存储由节点（nodes）组成的文档结构。与document相比，最大的区别是DocumentFragment 不是真实 DOM 树的一部分，它的变化不会触发 DOM 树的重新渲染，且不会导致性能等问题。
    //document (html body div)  remove(div) document(被改变 ---> 页面被改变
    //DocumentFragment  (相当于document 但是在内存中的)  remove(div)  --->页面不会被改变
    //DOM(页面)性能  重绘和回流

    //正常操作
/*    let liList = document.getElementsByTagName("li");
    Array.from(liList).forEach(item=>{
        item.innerHTML = "haha"
    })*/


//    <ul id="liBox">
    //    <li>[].slice.call(childNodes)</li>
    //    <li>Object.defineProperty</li>
    //    <li>Object.keys</li>
    //    <li>Object.hasOwnProperty</li>
    //    <li>node.nodeType</li>
    //    <li>createDocumentFragment</li>
//    </ul>



    //使用DocumentFragment
    let ul = document.getElementById("liBox");

//1.创建fragment
    let fragment = document.createDocumentFragment();

//2.取出ul中所有子节点放入fragment中  *每一个节点 都只能有一个父节点
//    console.log(ul.childNodes);
//[]
/*    for(let i=0;i<ul.childNodes.length;i++){
        let child = ul.childNodes[i];
        fragment.appendChild(child)
    }
  */

    while (ul.firstChild){
        fragment.appendChild(ul.firstChild)
    }


//3.修改更新fragment中所有的li的文本
//fragment.querySelectorAll("li")
console.log( fragment.childNodes)
    Array.prototype.slice.call(fragment.childNodes).forEach(nodeItem=>{
        console.log( nodeItem.nodeType);
        if(nodeItem.nodeType === 1){
            nodeItem.innerHTML = "haha"
        }

    });

//4.将fragment放入ul中
    ul.appendChild(fragment)

//vue中的虚拟DOM  使用js描述真实DOM
/**
 * <div id="app">
     <input v-model="name" :class="a" type="text" placeholder="姓名">
     <input v-model="age" type="text" placeholder="年龄">
     <input v-model="address" type="text" placeholder="地址">
     <input v-model="phoneNumber" type="text" placeholder="电话号码">
     <div>
     <ul>
         <li>姓名: {{name}}</li>
         <li>年龄: {{age}}</li>
         <li>地址: {{address}}</li>
         <li>
             <p>
             电话号码: {{phoneNumber}}
             </p>
         </li>
     </ul>
     </div>
 </div>
 */

/*var vDom ={
    id: 1,
    type:"div",
    attr: {
        id:"app"
    },
    ChildNode:[{
        id:2,
        type:"input",
        attr: {
            'v-model':"name",
            'type':"text",
            'placeholder':"姓名"
        },
    },{
        id:2,
        tag:"li",
        attr: {
            'v-model':"name",
            'type':"text",
            'placeholder':"姓名"
        },
        text: {
            str:"姓名: {{name}}",
            name: name
        }
    }]
}*/
</script>
<script>
    ////获取vm中data里相对应的属性值
    function getVMVal (data, exp){
        //exp ==> "a.b.c"
        exp = exp.split('.');//[a,b,c]


        exp.forEach((item)=>{//a //b //c
            data = data[item]
        });

        return data;
    }

    var obj = {
        a: {
            b: {
                c: 1
            }
        },
        name: "aa"
    };
    getVMVal(obj, "a.b.c")
//    obj["a.b.c"]
    //obj.a.b.c
</script>
</html>